/*
	ATI Radeon Mobility 9000 OpenGL Driver
	Copyright 2006, 2007  湖南泽天智航电子有限公司

  文件名：prof.c
  版本号：1.0.0
	修订记录：
	   20070330, RXH, Version 1.0.0 release
*/

// #define DOPROF
#ifdef DOPROF

#include "prof.h"
#include "math.h"
#include <unistd.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>

#include <pthread.h>
#include "prof.h"

pthread_key_t key;

PROFHANDLE g_handle;

void threadProfInit()
{
	static int flag = 0;
	if(flag == 0)
	{
		pthread_key_create(&key,NULL);
		memset(&g_handle,0,sizeof(PROFHANDLE));
		flag = 1;
	}
}

double gettimer()
{
	struct timeval tv;
	double tmp;
	gettimeofday(&tv,NULL);
	return (tv.tv_sec*1000000.0 + tv.tv_usec)/1000000.0;
}

PPROFHANDLE profInitEx()
{
	PPROFHANDLE pHandle;
	int i;
	pHandle = (PPROFHANDLE)malloc(sizeof(PROFHANDLE));
	threadProfInit();
	memset(pHandle,0,sizeof(PROFHANDLE));
	for (i = 0;i<PROFITEMCOUNT;i++)
	{
		pHandle->entertime[i] = gettimer();
		pHandle->profCount[i] = 0;
		pHandle->min[i] = 1.0;
	}
	pHandle->maxprofitem = 0;
	pthread_setspecific(key,pHandle);
	return pHandle;
}

void profInit()
{
	threadProfInit();
	PPROFHANDLE pHandle = (PPROFHANDLE)pthread_getspecific(key);
	if(pHandle == NULL)
	{
		pHandle = profInitEx();
	}
}

void profEnterSectEx(PPROFHANDLE pHandle,int sect)
{
	pHandle->entertime[sect] = gettimer();
	pHandle->profCount[sect]++;
	if (sect > pHandle->maxprofitem) 
	{
		pHandle->maxprofitem = sect;
	}
}

void profEnterSect(int sect)
{
	PPROFHANDLE pHandle = (PPROFHANDLE)pthread_getspecific(key);
	if(pHandle == NULL)
	{
		pHandle = profInitEx();
	}
	profEnterSectEx(pHandle,sect);
}


void profLeaveSectEx(PPROFHANDLE pHandle,int sect)
{
	double tmp;
	tmp = gettimer() - pHandle->entertime[sect];
	pHandle->totaltime[sect] += tmp;
	pHandle->cur[sect] = tmp;
	if(tmp < pHandle->min[sect])
	{
		pHandle->min[sect] = tmp;
	}
	if(tmp > pHandle->max[sect])
	{
		pHandle->max[sect] = tmp;
	}
	if (sect == 0)
	{
		int i;
		
		for (i = 0;i<PROFITEMCOUNT;i++)
			pHandle->entertime[i] = gettimer();
	}
}

void profLeaveSect(int sect)
{
	PPROFHANDLE pHandle = (PPROFHANDLE)pthread_getspecific(key);
	if(pHandle == NULL)
	{
		pHandle = profInitEx();
	}
	profLeaveSectEx(pHandle,sect);
}



void profSetSectNameEx(PPROFHANDLE pHandle,int sect, const char * pName)
{
	if (pHandle->profname[sect][0] == 0)
	{
		strncpy(pHandle->profname[sect], pName, NAMELEN-1);
		pHandle->profname[sect][NAMELEN-1] = 0;
	}
}

void profSetSectName(int sect, const char * pName)
{
	/*PPROFHANDLE pHandle = (PPROFHANDLE)pthread_getspecific(key);
	if(pHandle == NULL)
	{
		pHandle = profInitEx();
	}*/
	profSetSectNameEx(&g_handle,sect,pName);
}

void profPrintInfoEx(PPROFHANDLE pHandle)
{
	int i;
	double total;
	double item, other;
	unsigned long callcounter;
	unsigned long itemi;
	double min,max,avg,cur;
	/*read last counter*/
	total = (double)pHandle->totaltime[0];
	other = total;
	min = pHandle->min[0];
	max = pHandle->max[0];
	cur = pHandle->cur[0];
	avg = total/pHandle->profCount[0];
	printf("Total: %f,cur=%f,min=%f,avg=%f,max=%f\n", total,cur,min,avg,max);
	printf("pHandle = %p\n",pHandle);
	printf("\t%3s\t%-30s\t   %-10s %-10s %-10s %-10s %-8s %-6s  %s\n", 
			"No", "Name","cur","min","avg","max" ,"total", "per","count");
	for (i=1; i<=pHandle->maxprofitem; i++)
	{
		item = (double)pHandle->totaltime[i];
		other -= item;
		min = pHandle->min[i];
		max = pHandle->max[i];
		cur = pHandle->cur[i];
		avg = item/pHandle->profCount[i];
		printf("\t%03d\t%-30s\t%10.6f %10.6f %10.6f %10.6f %10.6f %6.3lf%%  [%ld]\n", 
			i, g_handle.profname[i],cur,min,avg,max ,item, item / total * 100,pHandle->profCount[i]);
	}
	/*其他未命名的项*/
	item = other;
	printf("\t%03d\t%-30s\t%10.5f %s%6.3lf%%\n", i, "$OTHERS$", item, (item<0)?"-":"", fabs(item) / total * 100);
}

void profPrintInfo()
{
	// printf("2.1\n");
	PPROFHANDLE pHandle = (PPROFHANDLE)pthread_getspecific(key);
	if(pHandle == NULL)
	{
		// printf("2\n");
		pHandle = profInitEx();
	}
	// printf("3\n");
	profPrintInfoEx(pHandle);
}


#ifdef PROFTEST 

void *profTestFunc(void *arg)
{
	int i;
	profEnterSect(0);
	for(i = 0; i < 100;i++)
	{
		profEnterSect(1);
		usleep(100);
		profLeaveSect(1);
		profEnterSect(2);
		usleep(200);
		profLeaveSect(2);
		profEnterSect(3);
		usleep(300);
		profLeaveSect(3);
	}
	profLeaveSect(0);
	profPrintInfo();
	return NULL;
}

int main()
{
	pthread_t ptid;
	profInit();
	profSetSectName(1,"name1");
	profSetSectName(2,"name2");
	profSetSectName(3,"name3");

	int i;
	for(i = 0;i < 10;i++)
	{
		pthread_create(&ptid,NULL,profTestFunc,&i);
	}
	
	profTestFunc(0);
	usleep(2000000);

}

#endif


#endif